package cn.pink.core.conf;

import cn.pink.core.config.IronConfig;
import cn.pink.core.support.JSONUtils;
import cn.pink.core.support.Log;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import cn.pink.core.support.SysException;
import cn.pink.core.support.Utils;

import java.io.*;
import java.lang.reflect.Field;
import java.util.*;
import java.util.Map.Entry;

/**
 * @author gaopan
 *
 * 配置基类
 */
public abstract class ConfBase {

	public static Map<Class, Map<String, Field>> tempClassField = new HashMap<>();
	
	/**
	 * 通过属性获取数据集合 支持排序
	 */
	public static <T extends ConfBase> List<T> utilBase(Collection<T> datas, Object...params) {
		List<Object> settings = Utils.ofList(params);
		
		/** 查询参数 */
		// 过滤条件
		Map<String, Object> paramsFilter = new LinkedHashMap<>();
		// 排序规则
		List<OrderByField> paramsOrder = new ArrayList<>();
				
		// 参数数量
		int len = settings.size();
		
		// 参数必须成对出现
		if (len % 2 != 0) {
			throw new SysException("查询参数必须成对出现:query={}", settings);
		}
		
		// 处理成对参数
		for (int i = 0; i < len; i += 2) {
			String key = (String)settings.get(i);
			Object val = settings.get(i + 1);
			
			// 参数 排序规则
			if (val instanceof OrderBy) {
				paramsOrder.add(new OrderByField(key, (OrderBy)val));
			// 参数 过滤条件
			} else {
				paramsFilter.put(key, val);
			}
		}
		
		// 返回结果
		List<T> result = new ArrayList<>();
		
		try {
			// 通过条件获取结果
			for (T c : datas) {
				// 本行数据是否符合过滤条件
				boolean bingo = true;
				
				// 判断过滤条件
				for (Entry<String, Object> p : paramsFilter.entrySet()) {
					// 实际结果
					Object valTrue = c.getFieldValue(p.getKey());
					// 期望结果
					Object valWish = p.getValue();
					
					// 有不符合过滤条件的
					if (!valWish.equals(valTrue)) {
						bingo = false;
						break;
					}
				}
				
				// 记录符合结果
				if (bingo) {
					result.add(c);
				}
			}
		} catch (Exception e) {
			throw new SysException(e);
		}
		
		// 对结果进行排序
		Collections.sort(result, (a, b) -> compareTo(a, b, paramsOrder));
		
		return result;
	}
	
	/**
	 * 获取指定字段的值
	 * @param key
	 * @return
	 */
	public abstract <T> T getFieldValue(String key);
	
	/**
	 * 创建组合key
	 * @param keys
	 * @return
	 */
	protected static String makeGroupKey(Object... keys) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < keys.length; ++i) {
			sb.append(String.valueOf(keys[i])).append("$");
		}
		
		// 去掉最后的"$"
		sb.deleteCharAt(sb.length() - 1);
		return sb.toString();
	}
	
	protected static <T extends ConfBase> void putMap(Map<String, List<T>> map, T value, Object...keys) {
		String key = ConfBase.makeGroupKey(keys);
		map.computeIfAbsent(key, (k) -> new ArrayList<>()).add(value);
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	private static <T extends ConfBase> int compareTo(T obj1, T obj2, List<OrderByField> paramsOrder) {
		try {
			for (OrderByField e : paramsOrder) {
				// 两方字段值
				Comparable va = obj1.getFieldValue(e.getKey());
				Comparable vb = obj2.getFieldValue(e.getKey());
				
				// 值排序结果
				int compareResult = va.compareTo(vb);
				
				// 相等时 根据下一个值进行排序
				if (va.compareTo(vb) == 0) {
					continue;
				}
				
				// 配置排序规则
				OrderBy order = e.getOrderBy();
				// 正序
				if (order == OrderBy.ASC) {
					return compareResult;
				// 倒序
				} else {
					return -1 * compareResult;
				}
			}
		} catch (Exception e) {
			throw new SysException(e);
		}

		return 0;
	}
	
	protected static int[] parseIntArray(String value) {
		return Utils.parseIntArray(value);
	}
	
	protected static long[] parseLongArray(String value) {
		return Utils.parseLongArray(value);
	}
	
	protected static float[] parseFloatArray(String value) {
		return Utils.parseFloatArray(value);
	}
	
	protected static double[] parseDoubleArray(String value) {
		return Utils.parseDoubleArray(value);
  	}

	protected static String[] parseStringArray(String value) {
		return Utils.parseStringArray(value);
	}

	protected static boolean[] parseBoolArray(String value) {
 		return Utils.parseBoolArray(value);
 	}

	protected static int[][] parseIntArray(String value, String split1, String split2) {
		if (StringUtils.isBlank(value)) {
			return new int[0][];
		}
		String[] arrayStr1 = value.split(split1);
		int len1 = arrayStr1.length;
		int[][] result = new int[len1][];
		for(int i=0; i<len1; ++i){
			String[] arrayStr2 = arrayStr1[i].split(split2);
			int len2 = arrayStr2.length;
			int[] array = new int[len2];
			for(int j=0; j<len2; ++j){
				array[j] = Utils.intValue(arrayStr2[j]);
			}
			result[i] = array;
		}
		return result;
	}

	protected static int[][] parseJson2IntArr(String value) {
		if (StringUtils.isBlank(value)) {
			return new int[0][];
		}

		value = "[" + value + "]";

		ObjectMapper mapper = JSONUtils.getJacksonMapper();
		int[][] result = null;
		try {
			List<List<Integer>> rows = mapper.readValue(value, new TypeReference<>(){});
			result = new int[rows.size()][];

			for(int i = 0; i < rows.size(); i++) {
				List<Integer> cols = mapper.readValue(rows.get(i)+"", new TypeReference<>(){});
				int[] array = new int[cols.size()];
				for(int j = 0; j < cols.size(); j++) {
					array[j] = Utils.intValue(cols.get(j)+"");
				}
				result[i] = array;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return result;
	}

	protected static long[][] parseLongArray(String value, String split1, String split2) {
		if (StringUtils.isBlank(value)) {
			return new long[0][];
		}
		String[] arrayStr1 = value.split(split1);
		int len1 = arrayStr1.length;
		long[][] result = new long[len1][];
		for(int i=0; i<len1; ++i){
			String[] arrayStr2 = arrayStr1[i].split(split2);
			int len2 = arrayStr2.length;
			long[] array = new long[len2];
			for(int j=0; j<len2; ++j){
				array[j] = Utils.longValue(arrayStr2[j]);
			}
			result[i] = array;
		}
		return result;
	}

	protected static long[][] parseJson2LongArr(String value) {
		if (StringUtils.isBlank(value)) {
			return new long[0][];
		}

		value = "[" + value + "]";

		ObjectMapper mapper = JSONUtils.getJacksonMapper();
		long[][] result = null;
		try {
			List<List<Long>> rows = mapper.readValue(value, new TypeReference<>(){});
			result = new long[rows.size()][];

			for(int i = 0; i < rows.size(); i++) {
				List<Long> cols = mapper.readValue(rows.get(i)+"", new TypeReference<>(){});
				long[] array = new long[cols.size()];
				for(int j = 0; j < cols.size(); j++) {
					array[j] = Utils.longValue(cols.get(j)+"");
				}
				result[i] = array;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return result;
	}

	protected static float[][] parseFloatArray(String value, String split1, String split2) {
		if (StringUtils.isBlank(value)) {
			return new float[0][];
		}
		String[] arrayStr1 = value.split(split1);
		int len1 = arrayStr1.length;
		float[][] result = new float[len1][];
		for(int i=0; i<len1; ++i){
			String[] arrayStr2 = arrayStr1[i].split(split2);
			int len2 = arrayStr2.length;
			float[] array = new float[len2];
			for(int j=0; j<len2; ++j){
				array[j] = Utils.floatValue(arrayStr2[j]);
			}
			result[i] = array;
		}
		return result;
	}

	protected static float[][] parseJson2FloatArr(String value) {
		if (StringUtils.isBlank(value)) {
			return new float[0][];
		}

		value = "[" + value + "]";

		ObjectMapper mapper = JSONUtils.getJacksonMapper();
		float[][] result = null;
		try {
			List<List<Float>> rows = mapper.readValue(value, new TypeReference<>(){});
			result = new float[rows.size()][];

			for(int i = 0; i < rows.size(); i++) {
				List<Float> cols = mapper.readValue(rows.get(i)+"", new TypeReference<>(){});
				float[] array = new float[cols.size()];
				for(int j = 0; j < cols.size(); j++) {
					array[j] = Utils.floatValue(cols.get(j)+"");
				}
				result[i] = array;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return result;
	}

	protected static double[][] parseDoubleArray(String value, String split1, String split2) {
		if (StringUtils.isBlank(value)) {
			return new double[0][];
		}
		String[] arrayStr1 = value.split(split1);
		int len1 = arrayStr1.length;
		double[][] result = new double[len1][];
		for(int i=0; i<len1; ++i){
			String[] arrayStr2 = arrayStr1[i].split(split2);
			int len2 = arrayStr2.length;
			double[] array = new double[len2];
			for(int j=0; j<len2; ++j){
				array[j] = Utils.doubleValue(arrayStr2[j]);
			}
			result[i] = array;
		}
		return result;
	}

	protected static double[][] parseJson2DoubleArr(String value) {
		if (StringUtils.isBlank(value)) {
			return new double[0][];
		}

		value = "[" + value + "]";

		ObjectMapper mapper = JSONUtils.getJacksonMapper();
		double[][] result = null;
		try {
			List<List<Double>> rows = mapper.readValue(value, new TypeReference<>(){});
			result = new double[rows.size()][];

			for(int i = 0; i < rows.size(); i++) {
				List<Double> cols = mapper.readValue(rows.get(i)+"", new TypeReference<>(){});
				double[] array = new double[cols.size()];
				for(int j = 0; j < cols.size(); j++) {
					array[j] = Utils.doubleValue(cols.get(j)+"");
				}
				result[i] = array;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return result;
	}

	protected static String[][] parseStringArray(String value, String split1, String split2) {
		if (StringUtils.isBlank(value)) {
			return new String[0][];
		}
		String[] arrayStr1 = value.split(split1);
		int len1 = arrayStr1.length;
		String[][] result = new String[len1][];
		for(int i=0; i<len1; ++i){
			String[] arrayStr2 = arrayStr1[i].split(split2);
			result[i] = arrayStr2;
		}
		return result;
	}

	protected static String[][] parseJson2StringArr(String value) {
		if (StringUtils.isBlank(value)) {
			return new String[0][];
		}

		value = "[" + value + "]";

		ObjectMapper mapper = JSONUtils.getJacksonMapper();
		String[][] result = null;
		try {
			List<List<Double>> rows = mapper.readValue(value, new TypeReference<>(){});
			result = new String[rows.size()][];

			for(int i = 0; i < rows.size(); i++) {
				List<Double> cols = mapper.readValue(rows.get(i)+"", new TypeReference<>(){});
				String[] array = new String[cols.size()];
				for(int j = 0; j < cols.size(); j++) {
					array[j] = cols.get(j)+"";
				}
				result[i] = array;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return result;
	}

	protected static boolean[][] parseBoolArray(String value, String split1, String split2) {
		if (StringUtils.isBlank(value)) {
			return new boolean[0][];
		}
		String[] arrayStr1 = value.split(split1);
		int len1 = arrayStr1.length;
		boolean[][] result = new boolean[len1][];
		for(int i=0; i<len1; ++i){
			String[] arrayStr2 = arrayStr1[i].split(split2);
			int len2 = arrayStr2.length;
			boolean[] array = new boolean[len2];
			for(int j=0; j<len2; ++j){
				array[j] = Utils.booleanValue(arrayStr2[j]);
			}
			result[i] = array;
		}
		return result;
	}

	protected static boolean[][] parseJson2BoolArr(String value) {
		if (StringUtils.isBlank(value)) {
			return new boolean[0][];
		}

		value = "[" + value + "]";

		ObjectMapper mapper = JSONUtils.getJacksonMapper();
		boolean[][] result = null;
		try {
			List<List<Boolean>> rows = mapper.readValue(value, new TypeReference<>(){});
			result = new boolean[rows.size()][];

			for(int i = 0; i < rows.size(); i++) {
				List<Boolean> cols = mapper.readValue(rows.get(i)+"", new TypeReference<>(){});
				boolean[] array = new boolean[cols.size()];
				for(int j = 0; j < cols.size(); j++) {
					array[j] = Utils.booleanValue(cols.get(j)+"");
				}
				result[i] = array;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return result;
	}

	protected static int[] parseIntArray(String value, String split) {
		return Utils.parseIntArray(value, split);
	}

	protected static long[] parseLongArray(String value, String split) {
		return Utils.parseLongArray(value, split);
	}

	protected static float[] parseFloatArray(String value, String split) {
		return Utils.parseFloatArray(value, split);
	}

	protected static double[] parseDoubleArray(String value, String split) {
		return Utils.parseDoubleArray(value, split);
	}

	protected static String[] parseStringArray(String value, String split) {
		return Utils.parseStringArray(value, split);
	}

	protected static boolean[] parseBoolArray(String value, String split) {
		return Utils.parseBoolArray(value, split);
	}

	protected static JSONObject parseStringToJson(String value) {
		if (StringUtils.isBlank(value)) {
			return null;
		}
		JSONObject json = JSONObject.parseObject(value);
		return json;
	}

	/**
	 * 读取游戏配置
	 */
	protected static String readConfFile(String name) {
		String result = "";
		//TODO 优先取平台对应的配置  这里可以改成按照玩家版本号(playerVersion)读取配置
		String filePath = new StringBuilder(IronConfig.RES_PATH).append("json/").append(name).append("_").append("playerVersion").append(".json").toString();

		File file = new File(filePath);
		// 如果平台对应的配置不存在，取默认配置
		if (!file.exists()) {
			filePath = new StringBuilder(IronConfig.RES_PATH).append("json/").append(name).append(".json").toString();
			file = new File(filePath);
		}

		try(BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) {
		    String tempString = "";
		    while ((tempString = reader.readLine()) != null) {
		    	result += tempString;
		    }
		} catch (IOException e) {
			Log.error.error("找不到指定json， path={}", filePath);
//		    throw new RuntimeException(e);
		} 
		
		return result;
	}

	public void reflectSet(Field filed, Object value){
		try {
			filed.set(this, value);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}
	
}
